#!/usr/bin/env python3

import json
import sys
import requests
import os
import datetime
from requests.exceptions import ConnectTimeout
import logging

logging.basicConfig(level=logging.INFO,#控制台打印的日志级别WARNING,INFO
                    filename='/var/log/zabbix/discovery_eureka.log',
                    filemode='a',##模式，有w和a，w就是写模式，每次都会重新写日志，覆盖之前的日志
                    #a是追加模式，默认如果不写的话，就是追加模式
                    format=
                    '%(asctime)s - %(pathname)s[line:%(lineno)d] - %(levelname)s: %(message)s'
                    #日志格式
                    )

def usage():
    print(sys.argv[0]+" <connection> (health|discover|get <item>)")
    sys.exit(1)

if len(sys.argv) < 2:
    usage()

TIMEOUT_REQUEST=2

BASE_URL = sys.argv[1]
ACTION = sys.argv[2]

def get_health(uri):
  uri=uri+"/actuator/health"
  try:
      r = requests.get(uri, headers={"Accept": "application/json"}, timeout=TIMEOUT_REQUEST)
      result = json.loads(r.text)
      print(result['status'])
  except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout):
      print("DOWN: unable to get state, connection/request timeout")
  except requests.exceptions.ConnectionError:
      print("DOWN: unable to get state, connection error")

def get_discovery(uri):
  uri=uri+"/eureka/apps"
  try:
  	r = requests.get(uri, headers={"Accept": "application/json"}, timeout=TIMEOUT_REQUEST)
  except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout):
      print("DOWN: unable to application data, connection/request timeout")
      sys.exit(1)
  except requests.exceptions.ConnectionError:
      print("DOWN: unable to application data, connection error")
      sys.exit(1)

  result = json.loads(r.text)
  data = []
  for app_data in result['applications']['application']:
      if  app_data['name'].find("TESTING") >= 0 or app_data['name'].find("INTEGRATION") >= 0:
        continue
      data.append({ '{#APPLICATION}': app_data['name'] })
  data = { "data":  data }
  print(json.dumps(data, indent=2, sort_keys=True))


def get_discovery_new(uri):
  logging.info("run get_discovery_new()")
  uri=uri+"/eureka/apps"
  try:
  	r = requests.get(uri, headers={"Accept": "application/json"}, timeout=TIMEOUT_REQUEST)
  except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout):
      print("DOWN: unable to application data, connection/request timeout")
      sys.exit(1)
  except requests.exceptions.ConnectionError:
      print("DOWN: unable to application data, connection error")
      sys.exit(1)

  result = json.loads(r.text)
  data = []
  for app_data in result['applications']['application']:
      if  app_data['name'].find("TESTING") >= 0 or app_data['name'].find("INTEGRATION") >= 0:
        continue
      for instance_data in app_data['instance']:
          # 不同的服务检测地址不同
          if app_data['name'] in ('GATEWAY-CONSOLE', 'GATEWAY-API', 'GATEWAY-TP'):
              checkUrl = "http://%s:%s/%s/doc.html" % (
              instance_data['ipAddr'], instance_data['port']['$'], instance_data['vipAddress'])
          else:
              checkUrl = "http://%s:%s/%s/serv" % (
              instance_data['ipAddr'], instance_data['port']['$'], instance_data['vipAddress'])
          logging.info("url:" + checkUrl)
          data.append({'{#APPLICATION}': app_data['name'] + "(" + instance_data['ipAddr'] + ":" + str(instance_data['port']['$']) + ")", '{#CHECKURL}': checkUrl})
  data = {"data":  data}
  print(json.dumps(data, indent=2, sort_keys=True))

def get_status(uri):
  CACHE_FILE = '/tmp/eureka_cache_%s_%s' % (uri.replace("/","\\"), os.getuid())
  cache_valid = False
  try:
    statinfo = os.stat(CACHE_FILE)
    if datetime.datetime.now().timestamp() - statinfo.st_mtime < 60:
      cache_valid = True
      fh = open(CACHE_FILE, 'r')
      text_fh0 = fh.read()
      result = json.loads(text_fh0)
  except (JSONDecodeError, json.JSONDecodeError) as je:
    logging.warning("JSONDecodeError! je:" + je + "text_fh0:" + text_fh0)
  except Exception as e:
    pass

  if not cache_valid:
    uri=uri+"/eureka/apps"
    try:
        r = requests.get(uri, headers={"Accept": "application/json"}, timeout=TIMEOUT_REQUEST)
        text_r0 = r.text
        result = json.loads(text_r0)
    except (JSONDecodeError, json.JSONDecodeError) as je:
        logging.warning("JSONDecodeError! je:" + je + "text_r0:" + text_r0)
    except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout):
        print("DOWN: unable to get state, connection/request timeout")
        sys.exit(1)
    except requests.exceptions.ConnectionError:
        print("DOWN: unable to get state, connection error")
        sys.exit(1)

    with open(CACHE_FILE, 'w') as fh:
        fh.write(json.dumps(result))

  data = {}
  for app_data in result['applications']['application']:
       instances = 0
       instances_good = 0
       for instance_data in app_data['instance']:
            instances += 1
            if instance_data['status'] == "UP":
               instances_good += 1
       if instances_good == instances:
           status = "OK: %s/%s" % (instances_good,instances)
       elif instances_good != 0:
           status = "WARN: %s/%s" % (instances_good,instances)
       else:
           status = "ERROR: %s/%s" % (instances_good,instances)
       
       data[app_data["name"]] = { "good": instances_good, "num": instances, "status": status }
  if len(sys.argv) != 4:
      print(json.dumps(data))
  else:
      try:
      	print(data[sys.argv[3]]["status"])
      except KeyError:
      	print("ERROR: UNKNOWN APPLICATION")

def check_app_status(uri):
  # 通过检测url地址来判断服务状态
  # 只要返回200状态即ok
  if len(sys.argv) != 4:
      print("loss arg! need 4 but find len(sys.argv).")
  else:
      try:
        app_name = sys.argv[3]
      except KeyError:
        print("ERROR: UNKNOWN APPLICATION")

  CACHE_FILE = '/tmp/eureka_cache_%s_%s' % (uri.replace("/","\\"), os.getuid())
  cache_valid = False
  result = {}
  try:
    statinfo = os.stat(CACHE_FILE)
    if datetime.datetime.now().timestamp() - statinfo.st_mtime < 600:
      cache_valid = True
      fh = open(CACHE_FILE, 'r')
      text_fh = fh.read()
      result = json.loads(text_fh)
  except (JSONDecodeError, json.JSONDecodeError) as je:
    logging.warning("JSONDecodeError! je:" + je + "text_fh:" + text_fh)
  except Exception as e:
    logging.warning("e:" + e)

  if not cache_valid:
    uri=uri+"/eureka/apps"
    try:
        r = requests.get(uri, headers={"Accept": "application/json"}, timeout=TIMEOUT_REQUEST)
        text_r = r.text
        result = json.loads(text_r)
    except (JSONDecodeError, json.JSONDecodeError) as je:
        logging.warning("JSONDecodeError! je:" + je + ",text:" + text_r)
    except (requests.exceptions.ConnectTimeout, requests.exceptions.ReadTimeout):
        print("DOWN: unable to get state, connection/request timeout")
        sys.exit(1)
    except requests.exceptions.ConnectionError:
        print("DOWN: unable to get state, connection error")
        sys.exit(1)
    except Exception as e:
        print("e:",e)
        sys.exit(1)

    with open(CACHE_FILE, 'w') as fh:
        fh.write(json.dumps(result))

  status = ""
  try:
    if ('applications' in result):
      pass
    else:
      logging.warning("not found applications key in result:" + result)
  except Exception as e:
    logging.warning("result:" + result + "e:" + e)
    print("result is warning")
    sys.exit(1)
  for app_data in result['applications']['application']:
    if app_data["name"] != app_name:
      continue
    instances = 0
    instances_good = 0
    for instance_data in app_data['instance']:
        instances += 1
        # statusPageUrl = instance_data['statusPageUrl']
        # 不同的服务检测地址不同
        if app_name in ('GATEWAY-CONSOLE','GATEWAY-API','GATEWAY-TP'):
          checkUrl = "http://%s:%s/%s/doc.html" % (instance_data['ipAddr'],instance_data['port']['$'],instance_data['vipAddress'])
        else:
          checkUrl = "http://%s:%s/%s/serv" % (instance_data['ipAddr'],instance_data['port']['$'],instance_data['vipAddress'])
        logging.info("url:" + checkUrl)
        try:
          r = requests.options(checkUrl, timeout=TIMEOUT_REQUEST)
          # print ("status_code:",r.status_code)
          if r.status_code == 200:
             instances_good += 1
        except Exception as e:
          print("checkUrl:",checkUrl,",e:",e)
    if instances_good == instances and instances != 0:
       status = "OK: %s/%s" % (instances_good,instances)
    elif instances_good != 0:
       status = "WARN: %s/%s" % (instances_good,instances)
    else:
       status = "ERROR: %s/%s" % (instances_good,instances)

  if status:
    print(status)
  else:
    print("ERROR: UNKNOWN APPLICATION")


def check_app_status_new(uri):
  # 通过检测url地址来判断服务状态
  # 只要返回200状态即ok

    status = ""
    try:
        r = requests.options(uri, timeout=TIMEOUT_REQUEST)
        logging.info("status_code:%s" % r.status_code)
        if r.status_code == 200:
            status = "OK: code:%s" % (r.status_code)
    except Exception as e:
        status = "WARN: code:%s,e:%s" % (r.status_code, e)
    if status:
        print(status)
    else:
        print("ERROR: status is null")


#######################################################################################################
### MAIN

if ACTION == "health":
  get_health(BASE_URL)
elif ACTION == "discover":
  get_discovery(BASE_URL)
elif ACTION == "discover2":
  get_discovery_new(BASE_URL)
elif ACTION == "get":
  get_status(BASE_URL)
elif ACTION == "check":
  check_app_status(BASE_URL)
elif ACTION == "check2":
  check_app_status_new(BASE_URL)
else:
   usage()

